/*
  Copyright 1996-2000
  Simon Whiteside

*/
package simkin.examples.applet;
import simkin.*;
import java.io.*;
import org.xml.sax.SAXException;
import org.w3c.dom.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;

/**
 * This class shows how you can use Simkin to show dialogs described in an XML script
*/
public class ScriptedDialog extends XMLExecutable implements ActionListener{
    /** 
     * this class holds the name and associated method name for a component
     */
    class ControlInfo {
	String m_Name="";
	String m_Method="";
	ControlInfo(String name,String method){
	    m_Name=name;
	    m_Method=method;
	}
    }
    /**
     * the parent frame
     */
    Frame m_Frame=new Frame();
    /**
     * the actual dialog created
     */
    Dialog m_Dialog;
    /**
     * a hashtable mapping controls to ControlInfo objects
     */
    Hashtable m_ControlInfo=new Hashtable();
    /**
     * Interpreter to use for method calls
     */
    Interpreter m_Interpreter;

    public ScriptedDialog(InputStream in,Interpreter interp) throws FileNotFoundException, SAXException, IOException{
	super("Dialog",in);
	m_Interpreter=interp;
	load();
    }
    /**
     * this method loads the dialog definition from the XML file
     */
    void load(){
	// extract the "dialog" tag from the document
	Element dialog=XMLElementObject.findChild(getElement(),"dialog");
	if (dialog!=null){
	    String title=dialog.getAttribute("title");
	    m_Dialog=new Dialog(m_Frame,title);
	    Panel dialogPanel=new Panel();
	    dialogPanel.setLayout(new FlowLayout());
	    loadControls(dialogPanel,dialog);
	    m_Dialog.add(dialogPanel);
	    int width=Integer.parseInt(dialog.getAttribute("width"));
	    int height=Integer.parseInt(dialog.getAttribute("height"));
	    m_Dialog.setSize(width,height);
	    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
	    m_Dialog.setLocation((d.width-width)/2,(d.height-height)/2);
	    m_Dialog.show();	
	    // call the init in the XML file
	    try{
		ExecutableContext context=new ExecutableContext(m_Interpreter);
		method("init",null,context);
	    }catch(Exception e){
		Tracer.trace(e);
	    }
	}
    }
    /**
     * this method loads controls from the controls sub-element of the given element
     * @param panel the panel the controls will be added to
     * @param element the owner of the controls element
     */
    void loadControls(Panel panel,Element element){
	Element controls=XMLElementObject.findChild(element,"controls");
	if (controls!=null){
	    NodeList control_list=controls.getChildNodes();
	    for (int i=0;i<control_list.getLength();i++){
		Node node=control_list.item(i);
		if (node.getNodeName().equals("control")){
		    Element control=(Element)node;
		    String type=control.getAttribute("type");
		    String text=control.getAttribute("text");
		    String name=control.getAttribute("name");
		    String method=control.getAttribute("method");
		    Component comp=null;
		    if (type.equals("static"))
			comp=new Label(text);
		    if (type.equals("edit"))
			comp=new TextField(text,20);
		    if (type.equals("button")){
			Button button=new Button(text);
			button.addActionListener(this);
			comp=button;
		    }
		    if (type.equals("panel")){
			Panel newPanel=new Panel();
			comp=newPanel;
			// load any controls in this panel
			loadControls(newPanel,control);
		    }
		    if (comp!=null){
			panel.add(comp);
			m_ControlInfo.put(comp,new ControlInfo(name,method));
		    }
		}
	    }
	}
    }
    /**
     * this method catches button clicks and calls methods
     */
    public void actionPerformed(ActionEvent e) {
	ControlInfo info=(ControlInfo)m_ControlInfo.get(e.getSource());
	if (info!=null){
	    try{
		ExecutableContext context=new ExecutableContext(m_Interpreter);
		method(info.m_Method,null,context);
	    }catch(Exception ex){
		Tracer.trace(ex);
	    }
	}
    }
    /**
     * This method shows a message box - because it is public it can be called from Simkin scripts
     */
    public void msgBox(String str){
	MsgBox msgBox=new MsgBox(m_Frame,str);
	msgBox.dispose();
    }
    /**
     * this method makes the dialog reload itself from the XML stream
     */
    public void reload(InputStream in){
	// recreate ourselves
	m_Dialog.hide();
	m_Dialog.dispose();
	try{
	    super.load("Dialog",in);
	    load();
	}catch (Exception e){
	    Tracer.trace(e);
	}
    }
    /**
     * This method closes the dialog  - because it is public it can be called from Simkin scripts
     */
    public void close(){
	m_Dialog.hide();
	m_Dialog.dispose();
    }
    /**
     * This method sets the focus to a particular control  - because it is public it can be called from Simkin scripts
     * @param name the control name
     */
    public void setFocus(String name){
	Component comp=findControl(name);
	if (comp!=null)
	    comp.requestFocus();
    }
    /**
     * This method returns the text in a text control  - because it is public it can be called from Simkin scripts
     * @param name the control name
     * @return the text in the control (or blank if the control is not a text control)
     */
    public String getText(String name){
	String return_value="";
	Component comp=findControl(name);
	if (comp!=null){
	    if (comp instanceof TextField)
		return_value=((TextField)comp).getText();
	}
	return return_value;
    }
    /**
     * this function finds a control with the given name
     */
    Component findControl(String name){
	Enumeration keys=m_ControlInfo.keys();
	Component found=null;
	while (keys.hasMoreElements()){
	    Component comp=(Component)keys.nextElement();
	    ControlInfo info=(ControlInfo)m_ControlInfo.get(comp);
	    if (info.m_Name.equals(name)){
		found=comp;
		break;
	    }
	}
	return found;
    }
}
